<?php

namespace App\Extends;

use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Database\Eloquent\ModelNotFoundException;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Request;
use PhpOffice\PhpSpreadsheet\IOFactory;
use App\Exceptions\BadException;

/**
 * @method bool setStatus(string $status) 更新订单状态
 */
abstract class BaseService
{
    protected $dao;

    public function __construct(BaseDao $dao)
    {
        $this->dao = $dao;
    }

    /**
     * 事务处理
     * @param callable $callback
     * @return mixed
     * @throws \Exception
     */
    public function transactional(callable $callback): mixed
    {
        DB::beginTransaction();

        try {
            $result = $callback();
            DB::commit();
            return $result;
        } catch (\Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * 分页获取
     * @param array $where
     * @return LengthAwarePaginator
     */
    public function paginate(array $where = []): LengthAwarePaginator
    {
        $page = Request::input('page', 1);
        $limit = Request::input('limit', 20);

        // 验证分页参数是否合理
        if (!is_numeric($page) || !is_numeric($limit) || $limit <= 0) {
            throw new \InvalidArgumentException("Invalid page or limit parameters.");
        }

        return $this->dao->paginate($where, (int) $limit, ['*'], 'page', (int) $page);
    }

    /**
     * 上传导入
     */
    public function import()
    {
        // 验证文件上传
        Request::validate([
            'file' => 'required|mimes:xlsx,xls,csv',
        ]);
        // 将文件存储到 storage/app/public/uploads 目录
        $path = Request::file('file')->storePublicly('public/uploads');
        // 获取文件的完整路径
        $fullPath = storage_path('app/' . $path);
        // 检查文件是否存在
        if (!file_exists($fullPath)) {
            throw new BadException('文件未找到，请检查文件路径', 400);
        }
        // 加载 Excel 文件
        $spreadsheet = IOFactory::load($fullPath);
        // 获取第一个工作表
        $worksheet = $spreadsheet->getActiveSheet();
        // 将工作表数据转换为数组
        $data = $worksheet->toArray();
        // 移除标题行
        $firstElement = array_shift($data);
        // 返回成功响应
        return $data;
    }

    /**
     * 调用给底层的 dao 对象
     * @param string $name
     * @param array $arguments
     * @return mixed
     */
    public function __call(string $name, array $arguments)
    {
        return call_user_func_array([$this->dao, $name], $arguments);
    }
}
